package org.rcy.ruicingmarket.gateway.filter;

import org.apache.commons.lang3.StringUtils;
import org.rcy.framework.cache.redis.CommonCache;
import org.rcy.ruicingmarket.cache.OssCacheGroup;
import org.rcy.ruicingmarket.cache.UmsCacheGroup;
import org.rcy.ruicingmarket.gateway.config.PermitedProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.net.URI;
import java.util.List;
import java.util.regex.Pattern;

/**
 * @author 吴康桥
 * @Description
 * @date 2022/10/12 16:04
 */


public class AddRequestContextGatewayFilterFactory extends AbstractGatewayFilterFactory<AddRequestContextGatewayFilterFactory.Config> {
	private Logger logger = LoggerFactory.getLogger(getClass());

	@Autowired
	private CommonCache commonCache;
	@Autowired
	private PermitedProperties permitedProperties;

	public AddRequestContextGatewayFilterFactory() {
		super(Config.class);
	}
	public static class Config {
	}

	@Override
	public GatewayFilter apply(Config config) {
		return (exchange, chain) -> {
			logger.debug("{}",exchange);
			if(isUnnecessarilyCheckedRequest(exchange)){
				return chain.filter(exchange);
			}
			if(isOssRequest(exchange)) {
				return ossReqFilter(exchange, chain);
			}
			if(isWebRequest(exchange)) {
				return webReqFilter(exchange, chain);
			}
			if(isFeignRequest(exchange)) {
				return chain.filter(exchange);
			}
			logger.warn("Invalid request, {}", exchange.getRequest().getURI());
			exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
			return exchange.getResponse().setComplete();
		};
	}

	private boolean isUnnecessarilyCheckedRequest(ServerWebExchange exchange){
		List<String> paths = permitedProperties.getPredicatesPaths();
		URI uri = exchange.getRequest().getURI();
		for (String path : paths) {
			Pattern pattern = Pattern.compile(resolvePath(path));
			if(pattern.matcher(uri.toString()).find()){
				return true;
			}
		}
		return false;
	}

	private String resolvePath(String path) {
		String pattern = null;
		if(path.indexOf("**") > 0) {
			pattern = ".*?"+path.substring(0, path.indexOf("*"))+"";
		}else {
			pattern = path;
		}
		return pattern;
	}

	private boolean isOssRequest(ServerWebExchange exchange){
		String ossToken = exchange.getRequest().getHeaders().getFirst("OSS-Token");
		return StringUtils.isNotBlank(ossToken);
	}

	private boolean isWebRequest(ServerWebExchange exchange){
		String webToken = exchange.getRequest().getHeaders().getFirst("WEB-Token");
		return StringUtils.isNotBlank(webToken);
	}

	private boolean isFeignRequest(ServerWebExchange exchange){
		String feignToken = exchange.getRequest().getHeaders().getFirst("feign-token");
		return StringUtils.isNotBlank(feignToken);
	}

	private Mono<Void> ossReqFilter(ServerWebExchange exchange, GatewayFilterChain chain){
		String ossToken = exchange.getRequest().getHeaders().getFirst("OSS-Token");
		if(StringUtils.isNotBlank(ossToken)){
			Object data = commonCache.getData(OssCacheGroup.OSS_USER, ossToken);
			if(data == null){
				logger.warn("Login status expired");
				exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
				HttpHeaders headers = exchange.getResponse().getHeaders();
				headers.add("LoginStatus","expired");
				//暴露token过期标识的响应头
				headers.add("Access-Control-Expose-Headers", "LoginStatus");
				return exchange.getResponse().setComplete();
			}
			ServerHttpRequest nheader = exchange.getRequest().mutate().header("ossInnerToken", ossToken).build();
			ServerWebExchange build = exchange.mutate().request(nheader).build();
			return chain.filter(build);
		}
		logger.warn("Invalid oss request, {}, {}", ossToken, exchange.getRequest().getURI());
		exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
		return exchange.getResponse().setComplete();
	}

	private Mono<Void> webReqFilter(ServerWebExchange exchange, GatewayFilterChain chain){
		String webToken = exchange.getRequest().getHeaders().getFirst("WEB-Token");
		if(StringUtils.isNotBlank(webToken)) {
			Object data = commonCache.getData(UmsCacheGroup.LOGINTOKEN);
			if(data == null) {
				logger.warn("Login status expired");
				exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
				HttpHeaders headers = exchange.getResponse().getHeaders();
				headers.add("LoginStatus","expired");
				//暴露token过期标识的响应头
				headers.add("Access-Control-Expose-Headers", "LoginStatus");
				return exchange.getResponse().setComplete();
			}
			ServerHttpRequest nheader = exchange.getRequest().mutate().header("webToken", webToken).build();
			ServerWebExchange build = exchange.mutate().request(nheader).build();
			return chain.filter(build);
		}
		logger.warn("Invalid web request, {}, {}", webToken, exchange.getRequest().getURI());
		exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
		return exchange.getResponse().setComplete();
	}
}
